查看原文
其他

别再用 BeanUtils 了,这款 PO VO DTO 转换神器真香!

点击关注 👉 Java技术图谱 2022-07-02

老铁们是不是经常为写一些实体转换的原始代码感到头疼?尤其是实体字段特别多的时候。


介绍一个开源项目 mapstruct ,可以轻松优雅的进行转换,简化你的代码。当然有的人喜欢写get set,或者用BeanUtils 进行复制,代码只是工具,本文只是提供一种思路。


先贴下官网地址吧:https://mapstruct.org/


废话不多说,上代码:


pom 配置:

<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <org.mapstruct.version>1.4.1.Final</org.mapstruct.version> <org.projectlombok.version>1.18.12</org.projectlombok.version></properties>

<dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> </dependency>

<!-- lombok dependencies should not end up on classpath --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${org.projectlombok.version}</version> <scope>provided</scope> </dependency>

<!-- idea 2018.1.1 之前的版本需要添加下面的配置,后期的版本就不需要了,可以注释掉,我自己用的2019.3 --> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> <scope>provided</scope> </dependency>

</dependencies>

<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${org.projectlombok.version}</version> </path> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>


关于lombok和mapstruct的版本兼容问题多说几句,maven插件要使用3.6.0版本以上、lombok使用1.16.16版本以上,另外编译的lombok mapstruct的插件不要忘了加上。否则会出现下面的错误:No property named "aaa" exists in source parameter(s). Did you mean "null"?


这种异常就是lombok编译异常导致缺少get setter方法造成的。还有就是缺少构造函数也会抛异常。

@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic class Student {

private String name; private int age; private GenderEnum gender; private Double height; private Date birthday;

}

public enum GenderEnum { Male("1", "男"), Female("0", "女");

private String code; private String name;

public String getCode() { return this.code; }

public String getName() { return this.name; }

GenderEnum(String code, String name) { this.code = code; this.name = name; }}

@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic class StudentVO { private String name; private int age; private String gender; private Double height; private String birthday;}

@Mapperpublic interface StudentMapper {

StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

@Mapping(source = "gender.name", target = "gender") @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") StudentVO student2StudentVO(Student student);

}


实体类是开发过程少不了的,就算是用工具生成肯定也是要有的,需要手写的部分就是这个Mapper的接口,编译完成后会自动生成相应的实现类



然后就可以直接用mapper进行实体的转换了


public class Test {

public static void main(String[] args) {

Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build(); System.out.println(student); //这行代码便是实际要用的代码 StudentVO studentVO = StudentMapper.INSTANCE.student2StudentVO(student); System.out.println(studentVO);

}

}



mapper可以进行字段映射,改变字段类型,指定格式化的方式,包括一些日期的默认处理。


可以手动指定格式化的方法:

@Mapperpublic interface StudentMapper {

StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

@Mapping(source = "gender", target = "gender") @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") StudentVO student2StudentVO(Student student);

default String getGenderName(GenderEnum gender) { return gender.getName(); }

}


上面只是最简单的实体映射处理,后面介绍一些高级用法


List 转换


属性映射基于上面的mapping配置

@Mapperpublic interface StudentMapper {

StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

@Mapping(source = "gender.name", target = "gender") @Mapping(source = "birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") StudentVO student2StudentVO(Student student);



List<StudentVO> students2StudentVOs(List<Student> studentList);

}

public static void main(String[] args) {

Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build();

List<Student> list = new ArrayList<>(); list.add(student); List<StudentVO> result = StudentMapper.INSTANCE.students2StudentVOs(list); System.out.println(result);}



1、多对象转换到一个对象


@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic class Student {

private String name; private int age; private GenderEnum gender; private Double height; private Date birthday;

}

@Data@AllArgsConstructor@Builder@NoArgsConstructorpublic class Course {

private String courseName; private int sortNo; private long id;

}

@Data@Builder@AllArgsConstructor@NoArgsConstructorpublic class StudentVO { private String name; private int age; private String gender; private Double height; private String birthday; private String course;}

@Mapperpublic interface StudentMapper {

StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

@Mapping(source = "student.gender.name", target = "gender") @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") @Mapping(source = "course.courseName", target = "course") StudentVO studentAndCourse2StudentVO(Student student, Course course);

}

public class Test {

public static void main(String[] args) {

Student student = Student.builder().name("小明").age(6).gender(GenderEnum.Male).height(121.1).birthday(new Date()).build(); Course course = Course.builder().id(1L).courseName("语文").build();

StudentVO studentVO = StudentMapper.INSTANCE.studentAndCourse2StudentVO(student, course); System.out.println(studentVO); }

}



默认值

@Mapperpublic interface StudentMapper {

StudentMapper INSTANCE = Mappers.getMapper(StudentMapper.class);

@Mapping(source = "student.gender.name", target = "gender") @Mapping(source = "student.birthday", target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss") @Mapping(source = "course.courseName", target = "course") @Mapping(target = "name", source = "student.name", defaultValue = "张三") StudentVO studentAndCourse2StudentVO(Student student, Course course);

}




Java技术交流群

有不少同学问我,大厂面试官到底喜欢问什么?想进大厂镀金。因此,我特意邀请了华为、腾讯、阿里的朋友进群,与大家一起交流经验,增长技术。

有兴趣入群的同学,可长按扫描下方二维码,一定要备注:城市+昵称+技术方向,根据格式备注,可更快被通过且邀请进群。

▲长按扫描


近期热文推荐



点个在看你最好看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存